package com.xingchi.tornado.storage.core.service.impl;

import com.xingchi.tornado.core.exception.ExceptionWrap;
import com.xingchi.tornado.core.utils.DigestUtils;
import com.xingchi.tornado.storage.core.FileStorageService;
import com.xingchi.tornado.storage.core.converter.DownloadFileHolder;
import com.xingchi.tornado.storage.core.exception.FileCode;
import com.xingchi.tornado.storage.core.exception.FileUploadException;
import com.xingchi.tornado.storage.core.model.FileUploadHolder;
import com.xingchi.tornado.storage.core.model.dto.FileDTO;
import com.xingchi.tornado.storage.core.model.dto.UserFileRelDTO;
import com.xingchi.tornado.storage.core.model.dto.UserFileRelQueryDTO;
import com.xingchi.tornado.storage.core.service.FileService;
import com.xingchi.tornado.storage.core.service.FileUploadService;
import com.xingchi.tornado.storage.core.service.UserFileRelService;
import com.xingchi.tornado.storage.core.utils.FileTypeChecker;
import com.xingchi.tornado.unique.provider.impl.SnowflakeProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.util.WebUtils;

import javax.activation.MimetypesFileTypeMap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

/**
 * 文件上传服务实现
 *
 * @author xingchi
 * @date 2024/5/4 21:37
 */
@Slf4j
@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private FileService fileService;
    @Autowired
    private UserFileRelService userFileRelService;
    @Autowired
    private SnowflakeProvider snowflakeProvider;


    /**
     * 上传文件
     *
     * @param fileUploadHolder 文件上传上下文
     * @return 用户文件关联信息
     */
    @Override
    public UserFileRelDTO uploadFile(FileUploadHolder fileUploadHolder) {

        if (fileUploadHolder.isEmpty()) {
            ExceptionWrap.cast(FileCode.FILE_UPLOAD_FAIL, "文件上传失败，找不到文件内容");
        }

        if (fileUploadHolder.getUserId() == null) {
            fileUploadHolder.setUserId(-1L);
        }


        Path path = null;
        try {

            // 先将文件写入到本地
            String suffix = FilenameUtils.getExtension(fileUploadHolder.getFileName());
            path = Files.createTempFile("tornado.file.", "." + suffix);
            // 执行写入
            long size;
            if (fileUploadHolder.getBytes() != null) {
                size = fileUploadHolder.getBytes().length;
                Files.copy(new ByteArrayInputStream(fileUploadHolder.getBytes()), path, StandardCopyOption.REPLACE_EXISTING);
            } else {
                size = Files.copy(fileUploadHolder.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
            }

            // 再查询文件是否存在
            String sha256 = DigestUtils.sha256(path.toFile());
            FileDTO fileDTO = fileService.selectBySha256(sha256);

            if (fileDTO == null) {
                // 新文件，执行上传操作逻辑
                String fileName = fileUploadHolder.getFileName();
                Integer type = FileTypeChecker.getFileTypeCode(fileName);
                fileDTO = FileDTO.builder()
                        .sha256(sha256)
                        .name(fileName)
                        .path(fileStorageService.uploadFile(path))
                        .size(size)
                        .type(type)
                        .suffix(suffix)
                        .build();
                fileService.insert(fileDTO);
            }

            // 构建用户文件联系直接插入
            UserFileRelDTO userFileRelDTO = UserFileRelDTO.builder()
                    .fileId(fileDTO.getId())
                    .userId(fileUploadHolder.getUserId())
                    .name(fileDTO.getName())
                    .path(fileDTO.getPath())
                    .size(fileDTO.getSize())
                    .suffix(fileDTO.getSuffix())
                    .type(fileDTO.getType())
                    .sha256(fileDTO.getSha256())
                    .build();
            userFileRelService.insert(userFileRelDTO);
            return userFileRelDTO;
        } catch (IOException e) {
            log.warn("文件上传失败，原因：{}", e.getMessage(), e);
            ExceptionWrap.cast(FileCode.FILE_UPLOAD_FAIL, e.getMessage());
        } finally {
            if (path != null && Files.exists(path)) {
                try {
                    Files.delete(path);
                } catch (IOException e) {
                    log.warn("文件删除失败，filePath: {}", path);
                }
            }
            IOUtils.closeQuietly(fileUploadHolder.getInputStream());
        }
        return null;
    }

    /**
     * 下载文件
     *
     * @param id 文件id
     */
    @Override
    public void download(Long id) {

    }

    /**
     * 下载文件
     *
     * @param path 文件路径
     */
    @Override
    public void download(String path) {

    }

    /**
     * 获取文件流
     *
     * @param id 文件id
     * @return 文件信息
     */
    @Override
    public DownloadFileHolder getInputStream(Long id) {

        UserFileRelDTO userFileRelDTO = userFileRelService.selectById(id);
        if (userFileRelDTO == null) {
            ExceptionWrap.cast(FileCode.FILE_NOT_FOUND, "文件不存在");
        }

        String path = userFileRelDTO.getPath();
        InputStream inputStream = fileStorageService.getInputStream(path);

        return new DownloadFileHolder(userFileRelDTO.getName(), userFileRelDTO.getSha256(), inputStream);
    }

    /**
     * 获取文件流
     *
     * @param path 文件路径
     * @return 文件信息
     */
    @Override
    public DownloadFileHolder getInputStream(String path) {

        UserFileRelDTO userFileRelDTO = userFileRelService.selectOne(UserFileRelQueryDTO.builder().path(path).build());
        if (userFileRelDTO == null) {
            ExceptionWrap.cast(FileCode.FILE_NOT_FOUND, "文件不存在");
        }

        InputStream inputStream = fileStorageService.getInputStream(path);

        return new DownloadFileHolder(userFileRelDTO.getName(), userFileRelDTO.getSha256(), inputStream);
    }
}
